﻿#include "init.h"
#include "camera.h"
#include "input.h"
#include "block.h"
#include "player.h"
#include "SkyBox.h"


#define SCREEN_WIDTH 1024
#define SCREEN_HEIGHT 768
#define CUSTOMFVF (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1)

#pragma comment (lib, "d3d9.lib")
#pragma comment (lib, "d3dx9.lib")
#pragma comment (lib, "dxguid.lib")
#pragma comment (lib, "dinput8.lib")

init* Init;
camera *playerCam;
input* playerInput;
player* gamePlayer;
SkyBox* sky;

block *gameWorld[100][100][100];
INT GameBlocks;

INT iX;
INT iY;
INT iZ;

INT PlayerBlock; 
bool area;
bool fly;

ID3DXFont * gFont = NULL;
RECT fade = { 20, 30, 180, 230 };
RECT Area, lBlock, sBlock, lPlayer, FlyMode;

D3DXVECTOR3 Pos; // PlayerPos
void CreateNewBlockPos(FLOAT X, FLOAT Y, FLOAT Z);
void drawWorld();
void drawSky();
void UpdatePlayer();

void CreateNewBlockPos(FLOAT X, FLOAT Y, FLOAT Z);



LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
void cleanD3D(void);
void render_frame(void);


template <class T>
std::string ToString(const T & t)
{
	std::ostringstream oss;
	oss.precision(2);
	oss.setf(std::ios_base::fixed);
	oss << t;
	return oss.str();
}

int WINAPI WinMain(HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPSTR lpCmdLine,
	int nCmdShow)
{
	HWND hWnd;
	WNDCLASSEX wc;
	ZeroMemory(&wc, sizeof(WNDCLASSEX));
	wc.cbSize = sizeof(WNDCLASSEX);
	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc = WindowProc;
	wc.hInstance = hInstance;
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.lpszClassName = "WindowClass";

	RegisterClassEx(&wc);

	hWnd = CreateWindowEx(NULL, "WindowClass", "BlockCraft",
		WS_OVERLAPPEDWINDOW, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT,
		NULL, NULL, hInstance, NULL);


	ShowWindow(hWnd, nCmdShow);



	SetRect(&Area, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
	SetRect(&FlyMode, 0, 50, 200, 300);

	SetRect(&fade, SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, SCREEN_WIDTH / 2 + 80, SCREEN_HEIGHT / 2 + 80);
	SetRect(&lBlock, 0, 100, 200, 200);
	SetRect(&sBlock, 0, 200, 200, 300);
	SetRect(&lPlayer, 100, 200, 200, 300);

	// INIT D3DX
	Init = new init(hWnd, SCREEN_WIDTH, SCREEN_HEIGHT);
	D3DXCreateFont(&(Init->getDevice()), 30, 0, FW_BOLD, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
		DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, TEXT("Arial"), &gFont);
	srand(255);
	playerCam = new camera(&(Init->getDevice()), (FLOAT)0.1f, (FLOAT)1000.0f);
	playerInput = new input(&(Init->getDevice()), hWnd);
	gamePlayer = new player();
	sky = new SkyBox(&(Init->getDevice()));

	PlayerBlock = 0;
	fly = false;
	for (int i = 0; i < 16; i++)
	{
		for (int j = 0; j < 16; j++)
		{
			gameWorld[i][j][1] = new block(&(Init->getDevice()), i, 2, j, 1);
		}
	}



	GetClientRect(hWnd, &Area);
	D3DXCreateFont(&(Init->getDevice()), 30, 0, FW_BOLD, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
		DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, TEXT("Arial"), &gFont);

	MSG msg;
	while (TRUE)
	{
		while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}

		if (msg.message == WM_QUIT)
		{
			break;
			// TODO MOUSE ACTIVE
		}
		render_frame();
	}

	cleanD3D();
	return msg.wParam;
}


LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
		break;
	}
	return DefWindowProc(hWnd, message, wParam, lParam);
}

void drawWorld()
{
	GameBlocks = 0;
	for (int i = 0; i < 100; i++)
	{
		for (int j = 0; j < 100; j++)
		{
			for (int k = 0; k < 100; k++)
			{
				if (gameWorld[i][j][k] != NULL)
				{
					GameBlocks++;
					Init->getDevice().SetTexture(0, gameWorld[i][j][k]->getTexture());
					Init->getDevice().SetStreamSource(0, gameWorld[i][j][k]->getVBuffer(), 0, sizeof(CUSTOMVERTEX));
					Init->getDevice().SetIndices(gameWorld[i][j][k]->getIBuffer());
					Init->getDevice().DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12); 
				}
			}
		}
	}
}

void drawSky()
{
	Init->getDevice().SetStreamSource(0, sky->getVBuffer(), 0, sizeof(CUSTOMVERTEX));
	Init->getDevice().SetIndices(sky->getIBuffer());
	Init->getDevice().DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12); 
}

void UpdatePlayer()
{
	Pos = D3DXVECTOR3(playerCam->GetPosition()->x, playerCam->GetPosition()->y, playerCam->GetPosition()->z);
	FLOAT X2 = Pos.x;
	FLOAT Y2 = Pos.y;
	FLOAT Z2 = Pos.z;
	iX = (INT)(((X2 - 6) / 6 + 1)) + INT((((((asin(playerCam->GetLook()->x) * 180 / 3.14) - 6) / 6) / 6 + 1)));
	iY = (INT)((Y2 - 6) / 6);
	iZ = (INT)(((Z2 - 6) / 6 + 1)) + INT((((((asin(playerCam->GetLook()->z) * 180 / 3.14) - 6) / 6) / 6 + 1)));

	Init->getDevice().SetFVF(CUSTOMFVF);
	Init->getDevice().SetTransform(D3DTS_VIEW, playerCam->GetViewMatrix());
	playerCam->update();

	playerInput->update();
	if (playerInput->kpressed(DIK_1)) PlayerBlock = 1;
	if (playerInput->kpressed(DIK_2)) PlayerBlock = 2;
	if (playerInput->kpressed(DIK_3)) PlayerBlock = 3;
	if (playerInput->kpressed(DIK_4)) PlayerBlock = 4;
	if (playerInput->kpressed(DIK_5)) PlayerBlock = 5;
	if (playerInput->kpressed(DIK_6)) PlayerBlock = 6;
	if (playerInput->kpressed(DIK_7)) PlayerBlock = 7;
	if (playerInput->kpressed(DIK_8)) PlayerBlock = 8;
	if (playerInput->kpressed(DIK_9)) PlayerBlock = 9;
	if (playerInput->kpressed(DIK_0)) PlayerBlock = 0;
		if (playerInput->kpressed(DIK_W)) playerCam->moveForward(1);
		if (playerInput->kpressed(DIK_S)) playerCam->moveForward(-1);
		if (playerInput->kpressed(DIK_D)) playerCam->moveLR(1);
		if (playerInput->kpressed(DIK_A)) playerCam->moveLR(-1);
		if (playerInput->kpressed(DIK_UP)) playerCam->moveUp(1);
		if (playerInput->kpressed(DIK_DOWN)) playerCam->moveUp(-1);
		if (playerInput->kpressed(DIK_ESCAPE)) PostQuitMessage(0);
	if (playerInput->kpressed(DIK_F))
	{
		playerCam->SetYMove(!(playerCam->GetYMove()));
		fly = !fly;
	}
	playerCam->pitch(playerInput->GetYDelta()*-0.002);
	playerCam->yaw(playerInput->GetXDelta()*0.002);


	if (area)
	{
		if (playerInput->kpressed(DIK_N))
		{
			gameWorld[iX][iY][iZ] = new block(&(Init->getDevice()), iX, iY, iZ, PlayerBlock);
		}
		if (playerInput->MouseButtonDown(1))
		{
			gameWorld[iX][iY][iZ] = new block(&(Init->getDevice()), iX, iY, iZ, PlayerBlock);
		}
		if (playerInput->MouseButtonDown(0))
		{
			if (gameWorld[iX][iY][iZ] != NULL)
			{
				gameWorld[iX][iY][iZ] = NULL;
			}
		}
	}
}


void render_frame(void)
{
	Init->getDevice().Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 255), 1.0f, 0);
	Init->getDevice().Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 255), 1.0f, 0);
	Init->getDevice().BeginScene();
	drawWorld();
	UpdatePlayer();

	gFont->DrawText(NULL, ToString("+").c_str(), -1, &fade, 0, D3DCOLOR_XRGB(255, 0, 0));

	if ((iX < 0) || (iY < 0) || (iZ < 0) || (iX > 100) || (iY > 100) || (iZ > 100))
	{
		gFont->DrawText(NULL, ToString("NO AREA").c_str(), -1, &Area, 0, D3DCOLOR_XRGB(255, 0, 0));
		area = false;
	}
	else
	{
		gFont->DrawText(NULL, ToString("BUILD AREA").c_str(), -1, &Area, 0, D3DCOLOR_XRGB(0, 255, 0));
		area = true;
	}

	gFont->DrawText(NULL, ToString("Block").c_str(), -1, &sBlock, 0, D3DCOLOR_XRGB(255, 255, 255));
	gFont->DrawText(NULL, ToString(PlayerBlock).c_str(), -1, &lPlayer, 0, D3DCOLOR_XRGB(255, 255, 255));
	if (fly)
	{
		gFont->DrawText(NULL, ToString("FLYMODE ON").c_str(), -1, &FlyMode, 0, D3DCOLOR_XRGB(255, 255, 255));
	}
	else
	{
		gFont->DrawText(NULL, ToString("FLYMODE OFF").c_str(), -1, &FlyMode, 0, D3DCOLOR_XRGB(255, 255, 255));
	}
	Init->getDevice().EndScene();

	Init->getDevice().Present(NULL, NULL, NULL, NULL);
}


void cleanD3D(void)
{
	//Init->v_buffer->Release();
	//Init->i_buffer->Release();
	Init->getDevice().Release();
	Init->getD3D().Release();
}

// CAMERA
/*D3DXMATRIX matView;
D3DXMatrixLookAtLH(&matView,
&D3DXVECTOR3(-30.0f, 12.0f, BEW-8.0f+25.0f),    // KAMERA POS VEC
&D3DXVECTOR3(LOOKX, 10.0f, BEW-8.0f),      // LOOK VEC
&D3DXVECTOR3(0.0f, 1.0f, 0.0f));    // UP VEC
Init->getDevice().SetTransform(D3DTS_VIEW, &matView);*/

//playerCam->updatePos(-30.0f, 0.0f, BEW);
//playerCam->updateLook(LOOKX, 0.0f, 0.0f);
// CAMERA

/*	for (int i = 0; i < 11; i++) // TODO WORLD CLASS
{
Z = -6.0f * i;
for (int j = 0; j < 12; j++)
{
Init->getDevice().SetStreamSource(0, Init->v_buffer2, 0, sizeof(CUSTOMVERTEX));
Init->getDevice().SetIndices(Init->i_buffer2);
D3DXMatrixTranslation(&matTranslateA[j], X, Y, Z);
Init->getDevice().SetTransform(D3DTS_WORLD, &(matTranslateA[j]));
Init->getDevice().DrawIndexedPrimitive(D3DPT_LINELIST, 0, 0, 24, 0, 12); // TODO BLOCK CLASS
Z = -6.0f * j;

}

X = X - 6.0f;
}

X = -6.0f;
Y = 0.0f;
Z = -6.0f;

for (int i = 0; i < 19; i++) // TODO WORLD CLASS
{
Z = -6.0f * i;
for (int j = 0; j < 20; j++)
{
Init->getDevice().SetStreamSource(0, Init->v_buffer, 0, sizeof(CUSTOMVERTEX));
Init->getDevice().SetIndices(Init->i_buffer);
D3DXMatrixTranslation(&matTranslateD[j], X, Y, Z);
Init->getDevice().SetTransform(D3DTS_WORLD, &(matTranslateD[j]));
Init->getDevice().DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 24, 0, 12); // TODO BLOCK CLASS

Z = -6.0f * j;
}

X = X - 6.0f;
} */

/*Init->getDevice().SetStreamSource(0, gameBlock->getVBuffer(), 0, sizeof(CUSTOMVERTEX));
Init->getDevice().SetIndices(gameBlock->getIBuffer());
Init->getDevice().DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 24, 0, 12); // TODO BLOCK CLASS

Init->getDevice().SetStreamSource(0, gameBlock2->getVBuffer(), 0, sizeof(CUSTOMVERTEX));
Init->getDevice().SetIndices(gameBlock2->getIBuffer());
Init->getDevice().DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 24, 0, 12); // TODO BLOCK CLASS*/

/*

if (playerCam->GetLook()->x < playerCam->GetLook()->z)
{
iZ = iZ + INT((((asin(1 + playerCam->GetLook()->y) * 180 / 3.14) / 6) - 3));
}
else if (playerCam->GetLook()->z < playerCam->GetLook()->x)
{
iX = iX + + INT((((asin(1 + playerCam->GetLook()->y) * 180 / 3.14) / 6) - 3));
}

*/